/*
 * Copyright (c) 2025 Li Auto Inc. and its affiliates
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * This file was generated form {{ Idlfilename }}.idl by the mvbs-idl-gen tool.
 */

{% import './general/typeRPC.jinja2' as RPC -%}
#include <mvbs/errno.h>
#include <mcdr/mcdr.h>

#include <mvbs/utils/log.h>
#include <mvbs/utils/string.h>
#include <mvbs/utils/mm.h>

#include <rpc/rpc.h>
#include "{{ Idlfilename }}RpcClient.h"

{% for node in constructMapList %}
{% for member in node.FuncMember %}

{%- if node.ModuleName -%}
	{% set interface_name = node.ModuleName ~ "_" ~ node.InterfaceName %}
{%- else -%}
	{% set interface_name = node.InterfaceName %}
{%- endif -%}

{%- set inputs = member.ParamIn | default([]) + member.ParamInout | default([]) -%}
{%- set outputs = member.ParamOut | default([]) + member.ParamInout | default([]) -%}

static int32_t {{ interface_name }}_{{ member.FuncName }}_cb(struct mvbs_cdr *stream, void *arg, int32_t error_flag)
{
	/* Interface name and operation name */
	char	interface[sizeof("{{ interface_name }}")];
	char	operation[sizeof("{{ member.FuncName }}")];
	{% if outputs != [] %}
	/* Param[OUT] */
	{{interface_name}}_{{member.FuncName}}_out res_type;
	{%- endif %}

	int32_t (*{{ member.FuncName }}_cb)({{RPC.FunctionOutputsParam(interface_name, member, outputs)}} int32_t rpc_errno);

	{{ member.FuncName }}_cb = arg;

	/* Case 1: error_flag Handling */
	if (error_flag) {
		int32_t rpc_errno = 0;

		if (mcdr_deserialize_int32_t(stream, &rpc_errno) == false)
			return -ERR_MCDR;

		/* maybe there is a error message in the future */
		return {{ member.FuncName }}_cb({{RPC.FunctionOutputsParam1(outputs)}}rpc_errno);
	}

	/* Case 2: Non-error_flag Handling */

	/* step1: deserialize interface name and operation name */
	if (mcdr_deserialize_string(stream, interface, sizeof("{{interface_name}}")) == false)
		return -ERR_MCDR;

	if (mcdr_deserialize_string(stream, operation, sizeof("{{member.FuncName}}")) == false)
		return -ERR_MCDR;
	{% if outputs != [] %}
	/*  step3: deserialize param[out] */
	if ({{interface_name}}_{{member.FuncName}}_deserialize_output_params(stream, &res_type) == false)
		return -ERR_MCDR;
	{%- endif %}

	/* step3: Call the real callback defined by user. */

	return {{ member.FuncName }}_cb({{RPC.FunctionOutputsParam1(outputs)}}0);

}

{% if "_stream" in member.FuncName and member.FuncName.split("_")[-1] == "stream" %}
int32_t {{ interface_name }}_{{ member.FuncName }}(struct rpc_client *cli, {{ RPC.FunctionInputsParam(interface_name, member, inputs)}}
			int32_t (*{{ member.FuncName }}_cb)({{ RPC.FunctionOutputsParam(interface_name, member, outputs)}}int32_t rpc_errno),
			uint32_t *sn, uint32_t timeout)
{
	char *req_buf		= NULL;
	int32_t ret		= 0;
	uint32_t req_size	= RPC_HEADER_SIZE;
	uint32_t default_sn	= RPC_INVALID_SN;
	struct mvbs_cdr stream;

	if (rpc_client_is_valid(cli) == false || {{ member.FuncName }}_cb == NULL)
		return -ERR_INVALID;

	if (sn == NULL)
		sn = &default_sn;

	req_size = get_size_of_{{interface_name}}_{{member.FuncName}}({{RPC.FunctionInputsParam1(inputs)}}req_size);

	/* step1: Initialize mcdr */
	req_buf = mvbs_malloc(req_size, MVBS_MM_ALIGN_DEFAULT);
	if (req_buf == NULL)
		return -ERR_NOMEM;

	mcdr_init_buffer(&stream, (uint8_t *)req_buf, req_size);

	/* step2: Install Callback Routine, and get a SN back */
	*sn = rpc_client_alloc_sn(cli, timeout, {{ interface_name }}_{{ member.FuncName }}_cb, {{ member.FuncName }}_cb, {{-RPC.InterfaceIsStream(member)-}}, *sn);
	if (*sn == RPC_INVALID_SN) {
		mvbs_free(req_buf);
		return -ERR_SNFAIL;
	}

	/* step3: serialize the rpc_header */
	ret = rpc_header_serialize(&stream, {{- RPC.InterfaceReqFlag(member)-}}, *sn, req_size - RPC_HEADER_SIZE);
	if (ret < 0) {
		rpc_client_free_sn(cli, *sn);
		mvbs_free(req_buf);
		return ret;
	}

	/*  step4: serialize the interface name */
	if (mcdr_serialize_string(&stream, "{{interface_name}}") == false)
		goto MCDR_FAIL;

	/*  step5: serialize the operation name */
	if (mcdr_serialize_string(&stream, "{{member.FuncName}}") == false)
		goto MCDR_FAIL;{{"\n"}}
	{%- if inputs != [] %}
	/* step6: serialize the interface/operation name and Param[in] */
	if ({{interface_name}}_{{member.FuncName}}_serialize_input_params(&stream, req_type) == false)
		goto MCDR_FAIL;
	{%- endif%}

	/* step7: Send the reqeust to server */
	ret = rpc_client_send(cli, req_buf, req_size);
	if ( ret < 0) {
		rpc_client_free_sn(cli, *sn);
		mvbs_free(req_buf);
		return -ERR_SEND;
	}

	mvbs_free(req_buf);

	return 0;

MCDR_FAIL:
	rpc_client_free_sn(cli, *sn);

	mvbs_free(req_buf);

	return -ERR_MCDR;
}
{%- else %}
int32_t {{ interface_name }}_{{ member.FuncName }}(struct rpc_client *cli, {{ RPC.FunctionInputsParam(interface_name, member, inputs)}}
			int32_t (*{{ member.FuncName }}_cb)({{ RPC.FunctionOutputsParam(interface_name, member, outputs)}} int32_t rpc_errno),
			uint32_t timeout)
{
	char *req_buf		= NULL;
	int32_t ret		= 0;
	uint32_t req_size	= RPC_HEADER_SIZE;
	uint32_t default_sn	= RPC_INVALID_SN;
	struct mvbs_cdr stream;

	if (rpc_client_is_valid(cli) == false || {{ member.FuncName }}_cb == NULL)
		return -ERR_INVALID;

	req_size = get_size_of_{{interface_name}}_{{member.FuncName}}({{RPC. FunctionInputsParam1(inputs)}}req_size);

	/* step1: Initialize mcdr */
	req_buf = mvbs_malloc(req_size, MVBS_MM_ALIGN_DEFAULT);
	if (req_buf == NULL)
		return -ERR_NOMEM;

	mcdr_init_buffer(&stream, (uint8_t *)req_buf, req_size);

	/* step2: Install Callback Routine, and get a SN back */
	default_sn = rpc_client_alloc_sn(cli, timeout, {{ interface_name }}_{{ member.FuncName }}_cb, {{ member.FuncName }}_cb, {{-RPC.InterfaceIsStream(member)-}}, default_sn);
	if (default_sn == RPC_INVALID_SN) {
		mvbs_free(req_buf);
		return -ERR_SNFAIL;
	}

	/* step3: serialize the rpc_header */
	ret = rpc_header_serialize(&stream, {{- RPC.InterfaceReqFlag(member)-}}, default_sn, req_size - RPC_HEADER_SIZE);
	if (ret < 0) {
		rpc_client_free_sn(cli, default_sn);
		mvbs_free(req_buf);
		return ret;
	}

	/*  step4: serialize the interface name */
	if (mcdr_serialize_string(&stream, "{{interface_name}}") == false)
		goto MCDR_FAIL;

	/*  step5: serialize the operation name */
	if (mcdr_serialize_string(&stream, "{{member.FuncName}}") == false)
		goto MCDR_FAIL;{{"\n"}}
	{%- if inputs != [] %}
	/* step6: serialize the interface/operation name and Param[in] */
	if ({{interface_name}}_{{member.FuncName}}_serialize_input_params(&stream, req_type) == false)
		goto MCDR_FAIL;
	{%- endif%}

	/* step7: Send the request to server */
	ret = rpc_client_send(cli, req_buf, req_size);
	if (ret < 0) {
		rpc_client_free_sn(cli, default_sn);
		mvbs_free(req_buf);
		return ret;
	}

	mvbs_free(req_buf);

	return 0;

MCDR_FAIL:
	rpc_client_free_sn(cli, default_sn);

	mvbs_free(req_buf);

	return -ERR_MCDR;
}
{%- endif %}

{% endfor %}
{% endfor %}
